package com.xinqi.modules.sys.textbook.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xinqi.common.base.error.CommonErrors;
import com.xinqi.common.base.response.PageInfo;
import com.xinqi.common.base.response.Param;
import com.xinqi.common.base.utils.tree.TreeHelp;
import com.xinqi.common.mybatis.utils.Pages;
import com.xinqi.common.mybatis.utils.Queries;
import com.xinqi.modules.sys.textbook.commonn.CommonPathUtils;
import com.xinqi.modules.sys.textbook.convert.CloudTextbookCatalogConvert;
import com.xinqi.modules.sys.textbook.domain.CloudTextbookCatalogEntity;
import com.xinqi.modules.sys.textbook.dto.req.CloudTextbookCatalogCreateDTO;
import com.xinqi.modules.sys.textbook.dto.req.CloudTextbookCatalogDeleteDTO;
import com.xinqi.modules.sys.textbook.dto.req.CloudTextbookCatalogQueryDTO;
import com.xinqi.modules.sys.textbook.dto.req.CloudTextbookCatalogUpdateDTO;
import com.xinqi.modules.sys.textbook.dto.rsp.CloudTextbookCatalogResultDTO;
import com.xinqi.modules.sys.textbook.enums.TextbookLimitEnum;
import com.xinqi.modules.sys.textbook.manager.CloudTextbookCatalogManager;
import com.xinqi.modules.sys.textbook.manager.CloudTextbookContentManager;
import com.xinqi.modules.sys.textbook.service.CloudTextbookCatalogService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.xinqi.common.base.error.CommonErrors.BAD_REQUEST;

/**
 * 云课本章节目录服务层实现
 *
 * @author: linkai
 * @date: 2023/04/25
 */
@Validated
@Service("cloudTextbookCatalogService")
@RequiredArgsConstructor
public class CloudTextbookCatalogServiceImpl implements CloudTextbookCatalogService {
    private final CloudTextbookCatalogConvert cloudTextbookCatalogConvert;
    private final CloudTextbookCatalogManager cloudTextbookCatalogManager;
    private final CloudTextbookContentManager cloudTextbookContentManager;

    /**
     * 分页查询 云课本章节目录数据
     */
    @Override
    @DS("slaver")
    public PageInfo<CloudTextbookCatalogResultDTO> page(Param pageable, CloudTextbookCatalogQueryDTO query) {
        IPage<CloudTextbookCatalogEntity> page = cloudTextbookCatalogManager.page(Pages.page(pageable), wrapper(query));
        return Pages.convert(page, cloudTextbookCatalogConvert::convert);
    }

    /**
     * 查询 云课本章节目录数据
     */
    @DS("slaver")
    @Override
    public List<CloudTextbookCatalogResultDTO> find(CloudTextbookCatalogQueryDTO query) {
        return cloudTextbookCatalogManager.list(wrapper(query)).stream()
            .map(cloudTextbookCatalogConvert::convert).collect(Collectors.toList());
    }

    private LambdaQueryWrapper<CloudTextbookCatalogEntity> wrapper(CloudTextbookCatalogQueryDTO query) {
        LambdaQueryWrapper<CloudTextbookCatalogEntity> wrapper = Queries.lambda();
        Queries.accept(query.getId(), v -> wrapper.eq(CloudTextbookCatalogEntity::getId, v));
        Queries.accept(query.getTextbookId(), v -> wrapper.eq(CloudTextbookCatalogEntity::getCloudTextbookId, v));
        Queries.accept(query.getName(), v -> wrapper.like(CloudTextbookCatalogEntity::getName, v));
        Queries.accept(query.getPId(), v -> wrapper.eq(CloudTextbookCatalogEntity::getPid, v));
        return wrapper;
    }

    /**
     * 根据id查询 云课本章节目录数据
     */
    @Override
    public CloudTextbookCatalogResultDTO findById(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        return Optional.ofNullable(cloudTextbookCatalogManager.findById(id)).map(cloudTextbookCatalogConvert::convert).orElse(null);
    }

    /**
     * 新增 云课本章节目录数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long insert(@Valid CloudTextbookCatalogCreateDTO dto) {
        CloudTextbookCatalogEntity entity = cloudTextbookCatalogConvert.create(dto);
        check(entity);
        // 设置目录路径
        setFilePath(entity);
        cloudTextbookCatalogManager.save(entity);
        return entity.getId();
    }

    private void setFilePath(CloudTextbookCatalogEntity entity) {
        if (entity.getPid() == 0L) {
            entity.setPath(CommonPathUtils.path(entity.getName()));
            entity.setLevel(CommonPathUtils.level(entity.getPath()));
            return;
        }
        CloudTextbookCatalogEntity parent = cloudTextbookCatalogManager.findById(entity.getPid());
        if (parent == null) {
            throw BAD_REQUEST.asException("父类节点不存在");
        }
        entity.setPath(CommonPathUtils.path(entity.getName(), parent.getPath()));
        entity.setLevel(CommonPathUtils.level(entity.getPath()));
        // 校验目录深度
        TextbookLimitEnum.文件夹深度.check(entity.getLevel());
    }

    /**
     * 根据id修改 云课本章节目录数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateById(@Valid CloudTextbookCatalogUpdateDTO dto) {
        CloudTextbookCatalogEntity old = Optional.ofNullable(cloudTextbookCatalogManager.getById(dto.getId()))
            .orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("数据不存在"));
        CloudTextbookCatalogEntity entity = cloudTextbookCatalogConvert.update(dto);
        entity.setPid(old.getPid());
        check(entity);
        setFilePath(entity);
        List<CloudTextbookCatalogEntity> list = new ArrayList<>();
        list.add(entity);
        setChildrenPath(list, entity.getId(), entity.getPath());
        return cloudTextbookCatalogManager.updateBatchById(list);
    }

    /**
     * 修改子节点路径
     */
    private void setChildrenPath(List<CloudTextbookCatalogEntity> list, Long pid, String path) {
        List<CloudTextbookCatalogEntity> children = cloudTextbookCatalogManager.findByPid(pid);
        children.forEach(v -> {
            CloudTextbookCatalogEntity entity = new CloudTextbookCatalogEntity();
            entity.setId(v.getId());
            entity.setPath(CommonPathUtils.path(v.getName(), path));
            entity.setLevel(CommonPathUtils.level(entity.getPath()));
            setChildrenPath(list, v.getId(), entity.getPath());
            list.add(entity);
        });
    }

    private void check(CloudTextbookCatalogEntity entity) {
        if (entity.getPid() == null) {
            entity.setPid(0L);
        }
        BAD_REQUEST.check(!entity.getName().contains("/"), "文件名称不能包含'/'字符");
        BAD_REQUEST.check(!isExistName(entity.getCloudTextbookId(), entity.getName(), entity.getPid(), entity.getId()), "名称已存在");
    }

    @Override
    public Boolean isExistName(Long textbookId, String name, Long pId, Long oId) {
        return cloudTextbookCatalogManager.isExistName(textbookId, name, pId, oId);
    }

    /**
     * 根据id删除 云课本章节目录数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        CommonErrors.BAD_REQUEST.check(!cloudTextbookCatalogManager.isExistChild(id), "已有子章节，不容许删除");
        // 清除章节下内容
        cloudTextbookContentManager.cleanByCatalogId(id);
        return cloudTextbookCatalogManager.removeById(id);
    }

    /**
     * 根据id删除 云课本章节目录数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(CloudTextbookCatalogDeleteDTO dto) {
        return deleteById(dto.getId());
    }

    @DS("slaver")
    @Override
    public List<CloudTextbookCatalogResultDTO> tree(Long textbookId) {
        CloudTextbookCatalogQueryDTO query = new CloudTextbookCatalogQueryDTO();
        query.setTextbookId(textbookId);
        List<CloudTextbookCatalogResultDTO> list = find(query);
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        return TreeHelp.<CloudTextbookCatalogResultDTO, Long>builder()
            .setList(list)
            .setChildren("children")
            .setParent("pid")
            .setComparator(Comparator.comparing(CloudTextbookCatalogResultDTO::getSort))
            .build()
            .handle(0L);
    }

    @DS("slaver")
    @Override
    public List<CloudTextbookCatalogResultDTO> findByCloudTextbookId(Long textBookId) {
        CloudTextbookCatalogQueryDTO query = new CloudTextbookCatalogQueryDTO();
        query.setTextbookId(textBookId);
        return cloudTextbookCatalogManager.list(wrapper(query)).stream()
            .map(cloudTextbookCatalogConvert::convert).collect(Collectors.toList());
    }
}
